﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Web.UI;
using System.Xml;

namespace MyChart
{
    /// <summary>
    /// 表示坐标系图表控件的抽象基类
    /// </summary>
    public abstract class Coordinate : FusionChart
    {
        #region 字段

        private string _dataSeriesField = "";
        private string _dataTextField = "";
        private string _dataValueField = "";

        private string _xAxisName = "";
        private string _yAxisName = "";
        private decimal _yAxisMinValue = 0;
        private decimal _yAxisMaxValue = 0;
        private int _horizontalLineCount = 4;
        private int _verticalLineCount = 0;
        private int _anchorRadius = 2;
        private bool _rotateLabel = true;
        private int _xAxisLabelStep = 0;

        private bool _multiSeriesMode = true;

        private MultiSeriesManager _itemManager;
        private Dictionary<string, SeriesConfig> _seriesConfigs = new Dictionary<string, SeriesConfig>();

        private CoordinateTargetLineCollection _targetLines = new CoordinateTargetLineCollection();

        #endregion

        #region 属性

        /// <summary>
        /// 获取或设置要从数据源绑定到数据项集合序列域的字段名
        /// </summary>
        public virtual string DataSeriesField
        {
            get { return _dataSeriesField; }
            set { _dataSeriesField = value; }
        }

        /// <summary>
        /// 获取或设置要从数据源绑定到数据项集合文本域的字段名
        /// </summary>
        public virtual string DataTextField
        {
            get { return _dataTextField; }
            set { _dataTextField = value; }
        }

        /// <summary>
        /// 获取或设置要从数据源绑定到数据项集合值域的字段名
        /// </summary>
        public virtual string DataValueField
        {
            get { return _dataValueField; }
            set { _dataValueField = value; }
        }

        /// <summary>
        /// 获取或设置x轴的标题文本
        /// </summary>
        public virtual string XAxisName
        {
            get { return _xAxisName; }
            set { _xAxisName = value; }
        }

        /// <summary>
        /// 获取或设置y轴的标题文本
        /// </summary>
        public virtual string YAxisName
        {
            get { return _yAxisName; }
            set { _yAxisName = value; }
        }

        /// <summary>
        /// 获取或设置y轴的最小值
        /// </summary>
        public virtual decimal YAxisMinValue
        {
            get { return _yAxisMinValue; }
            set { _yAxisMinValue = value; }
        }

        /// <summary>
        /// 获取或设置y轴的最大值（如果y轴的最大值等于最小值，则视为最大值由控件视情况自动设置）
        /// </summary>
        public virtual decimal YAxisMaxValue
        {
            get { return _yAxisMaxValue; }
            set { _yAxisMaxValue = value; }
        }

        /// <summary>
        /// 获取或设置坐标系横线数量
        /// </summary>
        public virtual int HorizontalLineCount
        {
            get { return _horizontalLineCount; }
            set { _horizontalLineCount = value; }
        }

        /// <summary>
        /// 获取或设置坐标系竖线数量
        /// </summary>
        public virtual int VerticalLineCount
        {
            get { return _verticalLineCount; }
            set { _verticalLineCount = value; }
        }

        /// <summary>
        /// 获取或设置坐标系中数据项的值对应的坐标点的半径
        /// </summary>
        public virtual int AnchorRadius
        {
            get { return _anchorRadius; }
            set { _anchorRadius = value; }
        }

        /// <summary>
        /// 获取或设置一个值，表示是否旋转x轴标签文本
        /// </summary>
        public virtual bool RotateLabel
        {
            get { return _rotateLabel; }
            set { _rotateLabel = value; }
        }

        /// <summary>
        /// 获取或设置一个值，表示x轴标签每隔多少显示一个
        /// </summary>
        public int XAxisLabelStep
        {
            get { return _xAxisLabelStep; }
            set { _xAxisLabelStep = value; }
        }

        /// <summary>
        /// 获取或设置一个值，表示y轴标签值每隔多少显示一个
        /// </summary>
        public int YAxisValuesStep  { get; set; }

        /// <summary>
        /// 获取或设置一个值，表示控件是否启用多序列模式（通过多序列Flash呈现数据）
        /// </summary>
        public virtual bool MultiSeriesMode
        {
            get { return _multiSeriesMode; }
            set { _multiSeriesMode = value; }
        }

        /// <summary>
        /// 获取或设置控件的数据项集合
        /// </summary>
        public virtual MultiSeriesManager ItemManager
        {
            get { return _itemManager; }
            set { _itemManager = value; }
        }

        /// <summary>
        /// 获取或设置序列配置字典
        /// </summary>
        public virtual Dictionary<string, SeriesConfig> SeriesConfigs
        {
            get { return _seriesConfigs; }
            set { _seriesConfigs = value; }
        }

        /// <summary>
        /// 获取或设置目标线对象集合
        /// </summary>
        public virtual CoordinateTargetLineCollection TargetLines
        {
            get { return _targetLines; }
            set { _targetLines = value; }
        }

        #endregion

        #region 事件

        /// <summary>
        /// 控件绑定数据前事件
        /// </summary>
        new public virtual event EventHandler<FusionChartDataBindingEventArgs> DataBinding;

        /// <summary>
        /// 控件绑定数据后事件
        /// </summary>
        public virtual event EventHandler<CoordinateDataBindedEventArgs> DataBinded;

        /// <summary>
        /// 控件绘制前事件
        /// </summary>
        public virtual event EventHandler<CoordinateRenderingEventArgs> Rendering;

        #endregion

        #region 构造器

        /// <summary>
        /// 初始化 Coordinate 类
        /// </summary>
        public Coordinate()
        {
            _itemManager = new MultiSeriesManager(this);
        }

        #endregion

        #region 抽象方法

        /// <summary>
        /// 要求子类实现获取控件的 FusionChart 完整Xml配置字符串方法
        /// </summary>
        /// <returns>完整的Xml配置字符串</returns>
        public abstract string GetRenderHtml();

        #endregion

        #region 方法

        /// <summary>
        /// 获取控件对应的flash文件路径
        /// </summary>
        /// <returns>flash文件路径</returns>
        protected override string GetFlashPath()
        {
            //获取当前控件实例的具体类型，然后通过类型名找到配置节点并根据_multiSeriesMode字段判断是否加载多序列flash文件
            string type = this.GetType().FullName;
            XmlNodeList listNodes = FusionChart.MyChartConfig.DocumentElement.SelectNodes("/myChart/mappingGroup/mapping");
            foreach (XmlNode xmlNode in listNodes)
            {
                if (xmlNode.Attributes["type"] != null && xmlNode.Attributes["type"].Value == type)
                {
                    if (!_multiSeriesMode)
                    {
                        if (xmlNode.Attributes["flash"] == null || string.IsNullOrEmpty(xmlNode.Attributes["flash"].Value))
                        {
                            throw (new Exception("控件'" + type + "'没有映射单序列flash文件路径。"));
                        }
                        else
                        {
                            return xmlNode.Attributes["flash"].Value;
                        }
                    }
                    else
                    {
                        if (xmlNode.Attributes["flashMS"] == null || string.IsNullOrEmpty(xmlNode.Attributes["flashMS"].Value))
                        {
                            throw (new Exception("控件'" + type + "'没有映射多序列flash文件路径。"));
                        }
                        else
                        {
                            return xmlNode.Attributes["flashMS"].Value;
                        }
                    }
                }
            }
            throw (new Exception("没有找到控件'" + type + "'的flash路径映射节点。"));
        }

        /// <summary>
        /// 重写 System.Web.UI.Control 基类的 OnInit 初始化事件
        /// </summary>
        /// <param name="e">事件参数</param>
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            if (_itemManager != null)
            {
                _itemManager.Chart = this;
            }
        }

        /// <summary>
        /// 重写 System.Web.UI.Control 基类的 OnPreRender 绘制前事件
        /// </summary>
        /// <param name="e">事件参数</param>
        protected override void OnPreRender(EventArgs e)
        {
            if (!Page.ClientScript.IsClientScriptIncludeRegistered("MyChart"))
            {
                Page.ClientScript.RegisterClientScriptInclude("MyChart", Page.ClientScript.GetWebResourceUrl(this.GetType(), "MyChart.Resource.FusionCharts.js"));
            }

            base.OnPreRender(e);
        }

        /// <summary>
        /// 重写 System.Web.UI.Control 基类的 RenderControl 绘制控件方法
        /// </summary>
        /// <param name="writer">html绘制输出流</param>
        public override void RenderControl(HtmlTextWriter writer)
        {
            //触发控件绘制前事件
            if (Rendering != null)
            {
                CoordinateRenderingEventArgs args = new CoordinateRenderingEventArgs(_itemManager);
                Rendering(this, args);
            }

            base.RenderControl(writer);

            string sChartXML = FormatRenderHtml(GetRenderHtml());   //执行GetRenderHtml之后_itemManager.DictArguments才绑定值

            writer.Write(FusionRender.RenderChart(_itemManager.IsEmpty, GetFlashPath(), "sChartXML", sChartXML, ClientID, Width.ToString(), Height.ToString(), _itemManager.DictArguments, base.IsCustomRender));
        }

        /// <summary>
        /// 执行控件数据绑定
        /// </summary>
        public override void DataBind()
        {
            DataView view;
            //创建_dataSeriesField，_dataValueField，_dataTextField的临时变量
            string dataSeriesField = _dataSeriesField;
            string dataValueField = _dataValueField;
            string dataTextField = _dataTextField;

            //判断数据源是哪种类型
            if (DataSource == null)
            {
                return;
            }
            else if (DataSource is DataSet)
            {
                view = (DataSource as DataSet).Tables[0].DefaultView;
            }
            else if (DataSource is DataTable)
            {
                view = (DataSource as DataTable).DefaultView;
            }
            else if (DataSource is DataView)
            {
                view = DataSource as DataView;
            }
            else if (DataSource is MultiDimensionalDataSource)
            {
                //如果数据源是多维数据源，则通过_dataSeriesField，_dataTextField设置数据源的相关字段
                (DataSource as MultiDimensionalDataSource).DataSeriesField = _dataSeriesField;
                (DataSource as MultiDimensionalDataSource).DataTextField = _dataTextField;

                //调用多维数据源的GetDataSource方法，获取多维数据源转换格式后的数据源
                view = (DataSource as MultiDimensionalDataSource).GetDataSource();

                //由于换格式后的数据源对应中序列字段，值字段，文本字段发生了改变
                //所以需要重新设置临时变量dataSeriesField，dataValueField，dataTextField
                dataSeriesField = (DataSource as MultiDimensionalDataSource).AutoSeriesFieldName;
                dataValueField = (DataSource as MultiDimensionalDataSource).AutoValueFieldName;
                dataTextField = (DataSource as MultiDimensionalDataSource).AutoTextFieldName;

                //调用多维数据源的GetSeriesConfigs获取转换后的序列配置对象集合，并赋值给控件的序列配置对象集合
                Dictionary<string, SeriesConfig> sc = (DataSource as MultiDimensionalDataSource).GetSeriesConfigs();
                foreach (string key in sc.Keys)
                {
                    _seriesConfigs[key] = sc[key];
                }
            }
            else
            {
                throw (new Exception("DataSource不是有效的数据源！"));
            }

            //触发数据绑定前事件
            if (DataBinding != null)
            {
                FusionChartDataBindingEventArgs args = new FusionChartDataBindingEventArgs(view);
                DataBinding(this, args);
            }

            //获取数据源中数据项的文本集合
            _itemManager.Texts.Clear();
            foreach (DataRowView drv in view)
            {
                string text = drv[dataTextField].ToString();
                if (!_itemManager.Texts.Contains(text))
                {
                    _itemManager.Texts.Add(text);
                }
            }

            //获取数据源中数据项序列的标识集合
            _itemManager.Series.Clear();
            List<string> series = new List<string>();
            if (!string.IsNullOrEmpty(dataSeriesField))
            {
                foreach (DataRowView drv in view)
                {
                    string seriesName = drv[dataSeriesField].ToString();
                    if (!series.Contains(seriesName))
                    {
                        series.Add(seriesName);
                    }
                }
            }

            if (series.Count > 0)
            {
                //通过序列标识和文本集合获取数据源中的数据项，并加入到数据项集合中
                foreach (string seriesName in series)
                {
                    ChartSeries s = new ChartSeries();
                    s.Name = seriesName;
                    if (_seriesConfigs.ContainsKey(s.Name))
                    {
                        s.Color = _seriesConfigs[s.Name].Color;
                        s.IsDashed = _seriesConfigs[s.Name].IsDashed;
                        s.ParentYAxis = _seriesConfigs[s.Name].ParentYAxis;
                        s.RenderType = _seriesConfigs[s.Name].RenderType;
                        s.ShowAnchors = _seriesConfigs[s.Name].ShowAnchors;
                        s.ShowValues = _seriesConfigs[s.Name].ShowValues;
                        s.ToolTextFormat = _seriesConfigs[s.Name].ToolTextFormat;
                        s.OnClientClick = _seriesConfigs[s.Name].OnClientClick;
                    }
                    foreach (string text in _itemManager.Texts)
                    {
                        //通过序列标识和文本筛选数据源中唯一的数据行
                        view.RowFilter = dataTextField + "='" + text + "' AND " + dataSeriesField + "='" + seriesName + "'";
                        ChartItem item = new ChartItem();
                        if (view.Count > 0)
                        {
                            item.Value = view[0][dataValueField].ToString();
                            item.Text = text;
                            item.Row = view[0];
                        }
                        s.Items.Add(item);
                    }
                    _itemManager.Series.Add(s);
                }
            }
            else
            {
                ChartSeries s = new ChartSeries();
                foreach (string text in _itemManager.Texts)
                {
                    //通过序列标识和文本筛选数据源中唯一的数据行
                    view.RowFilter = dataTextField + "='" + text + "'";
                    ChartItem item = new ChartItem();
                    if (view.Count > 0)
                    {
                        item.Value = view[0][dataValueField].ToString();
                        item.Text = text;
                        item.Row = view[0];
                    }
                    s.Items.Add(item);
                }
                _itemManager.Series.Add(s);
            }

            //触发数据绑定后事件
            if (DataBinded != null)
            {
                CoordinateDataBindedEventArgs args = new CoordinateDataBindedEventArgs(view, _itemManager);
                DataBinded(this, args);
            }
        }

        /// <summary>
        /// 获取控件的数据项集合的FusionChart Xml字符串
        /// </summary>
        /// <returns>控件的数据项集合的FusionChart Xml字符串</returns>
        protected string GetItemManagerXmlString()
        {
            //如果开启了多序列模式，则直接返回_itemManager的fusionchart多序列格式的xml字符串
            //否则创建一个临时的但序列数据项集合ssm，并把_itemManager中第0个序列的所有item赋值给ssm
            //再调用ssm的GetXmlString方法获取fusionchart单序列格式的xml字符串
            if (MultiSeriesMode)
            {
                return _itemManager.GetXmlString();
            }
            else
            {
                SingleSeriesManager ssm = new SingleSeriesManager(this);
                if (_itemManager.Series.Count > 0)
                {
                    foreach (ChartItem item in _itemManager.Series[0].Items)
                    {
                        ssm.Items.Add(item);
                    }
                }
                string sChartXML = ssm.GetXmlString();  //DictArguments是在执行这个方法后才被附值
                _itemManager.DictArguments = ssm.DictArguments;
  
                return sChartXML;
            }
        }

        /// <summary>
        /// 获取控件的目标线集合的FusionChart Xml字符串
        /// </summary>
        /// <returns>控件的目标线集合的FusionChart Xml字符串</returns>
        protected string GetTargetLinesXmlString()
        {
            return _targetLines.GetXmlString();
        }

        #endregion
    }
}
